<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>

    <!-- ======================== FILTER CHAIN ======================= -->

    <!--  if you wish to use channel security, add "channelProcessingFilter," in front
         of "httpSessionContextIntegrationFilter" in the list below -->
    <!--
         FilterChainProxy会按顺序来调用这些filter,使这些filter能享用Spring ioc的功能,
         CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定义了url比较前先转为小写
         PATTERN_TYPE_APACHE_ANT定义了使用Apache ant的匹配模式


          如果不需要附加码，去掉captchaValidationProcessingFilter,channelProcessingFilter,过滤器


		 去掉rememberMeProcessingFilter,anonymousProcessingFilter,
     -->
    <bean id="filterChainProxy"
          class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor
            </value>
        </property>
    </bean>

    <!-- ======================== AUTHENTICATION ======================= -->

    <!--
         通过Providers提供认证者列表,如果一个认证提供者失败可以尝试另外一个认证提供者,以保证获取不同来源的身份认证，如
         DaoAuthenticationProvider 从数据库中读取用户信息验证身份





         AnonymousAuthenticationProvider 匿名用户身份认证
         RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证

         其它的还有






         AuthByAdapterProvider 使用容器的适配器验证身份






         CasAuthenticationProvider 根据Yale中心认证服务验证身份, 用于实现单点登陆
         JaasAuthenticationProvider 从JASS登陆配置中获取用户信息验证身份






         RemoteAuthenticationProvider 根据远程服务验证用户身份
         RunAsImplAuthenticationProvider 对身份已被管理器替换的用户进行验证






         X509AuthenticationProvider 从X509认证中获取用户信息验证身份






         TestingAuthenticationProvider 单元测试时使用







         每个认证者会对自己指定的证明信息进行认证，如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证。






     -->
    <bean id="authenticationManager"
          class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <list>
                <ref local="staticDaoAuthenticationProvider"/>
                <ref local="domainDaoAuthenticationProvider"/>
                <ref local="staticDaoAuthenticationProviderChinese"/>
                <ref local="dynamicDaoAuthenticationProvider"/>
                <ref local="dynamicDaoAuthenticationProviderChinese"/>
                <ref local="kingdeeDaoAuthenticationProvider"/>
                <ref local="rtxDaoAuthenticationProvider"/>
                <ref local="rtxDaoAuthenticationProviderChinese"/>
		
                <!-- PT056407, R111009-0403, hao_yun, 将v6.2R1中的IM集成回迁至v6.1 -->
                <ref local="ucstarDaoAuthenticationProvider"/>
                <ref local="ucstarDaoAuthenticationProviderEAS"/>
		
                <!-- 只保留一不数据库的登陆 -->
                <!-- ref local="anonymousAuthenticationProvider"/ -->
                <!-- ref local="rememberMeAuthenticationProvider"/ -->
                <!-- testingAuthenticationProvider仅供测试环境用，正式生产平台请去除 -->
                <!-- ref local="testingAuthenticationProvider"/ -->
            </list>
        </property>
    </bean>

    <!--
		jdbcDaoImpl 用于在数据中获取用户信息。




		acegi提供了用户及授权的表结构，但是您也可以自己来实现。




		通过usersByUsernameQuery这个SQL得到你的(用户ID,密码,状态信息)
		通过authoritiesByUsernameQuery这个SQL得到你的(用户ID,授权信息)
		
		???对于多种认证方式，看这个地方需要怎么改???
     -->
     
    <bean id="jdbcDaoImpl"
          class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
        <property name="dataSource">
        	<ref bean="dataSource"/>
        </property>
        <property name="usersByUsernameQuery">
            <value>
                select loginid,password,1 from system_users where status='1' and loginid=?
            </value>
        </property>
        <property name="authoritiesByUsernameQuery">
            <value>
				select u.loginid, p.name 
				from system_users u,system_roles r,system_perms p,system_user_role ur,system_role_perm rp 
				where u.id=ur.user_id and r.id=ur.role_id and p.id=rp.perm_id 
				and r.id=rp.role_id and p.status='1'  and u.loginid=?
            </value>
        </property>
    </bean>
    
    <bean id="ucstarJdbcDaoImpl"
          class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
        <property name="dataSource">
        	<ref bean="dataSource"/>
        </property>
        <property name="usersByUsernameQuery">
            <value>
                select loginid,password,1 from system_users where status='1' and eas_loginid=?
            </value>
        </property>
        <property name="authoritiesByUsernameQuery">
            <value>
				select u.loginid, p.name 
				from system_users u,system_roles r,system_perms p,system_user_role ur,system_role_perm rp 
				where u.id=ur.user_id and r.id=ur.role_id and p.id=rp.perm_id 
				and r.id=rp.role_id and p.status='1'  and u.loginid=?
            </value>
        </property>
    </bean>
    
    <!-- 使用中文登录，dynamicno暂时做为中文名转码后的存放字段 -->
    <bean id="jdbcDaoImplChinese"
          class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
        <property name="dataSource">
        	<ref bean="dataSource"/>
        </property>
        <property name="usersByUsernameQuery">
            <value>
                select loginid,password,1 from system_users where status='1' and username=?
            </value>
        </property>
        <property name="authoritiesByUsernameQuery">
            <value>
				select u.loginid, p.name 
				from system_users u,system_roles r,system_perms p,system_user_role ur,system_role_perm rp 
				where u.id=ur.user_id and r.id=ur.role_id and p.id=rp.perm_id 
				and r.id=rp.role_id and p.status='1'   and u.loginid=?
            </value>
        </property>
    </bean>      
    <!-- 使用Md5算法加密 -->
    <bean id="passwordEncoder"
          class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>

	<bean id="plaintextPasswordEncoder"
          class="org.acegisecurity.providers.encoding.PlaintextPasswordEncoder"/>

    <!--
         userDetailsService 定义jdbcDaoImpl从数据库获取用户信息
         userCache ehcache缓存user信息。






         passwordEncoder 取得密码后作加密
     -->
    <bean id="daoAuthenticationProvider"
          class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
    </bean>

    <bean id="staticDaoAuthenticationProvider"
          class="org.springside.modules.security.service.acegi.provider.StaticDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
        <property name="captchaCheck">
        	<!-- 设置为false则不进行验证码的处理，默认设置为true -->
        	<value>${plugins.imagerand}</value>
        </property>
    </bean>   
    
    <bean id="domainDaoAuthenticationProvider"
          class="org.springside.modules.security.service.acegi.provider.DomainDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="plaintextPasswordEncoder"/>
        </property>
        <property name="captchaCheck">
        	<!-- 设置为false则不进行验证码的处理，默认设置为true -->
        	<value>${plugins.imagerand}</value>
        </property>
    </bean>
    
    <bean id="staticDaoAuthenticationProviderChinese"
          class="org.springside.modules.security.service.acegi.provider.StaticDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImplChinese"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
        <property name="captchaCheck">
        	<!-- 设置为false则不进行验证码的处理，默认设置为true -->
        	<value>${plugins.imagerand}</value>
        </property>
    </bean>     
    
    <bean id="dynamicDaoAuthenticationProvider"
          class="org.springside.modules.security.service.acegi.provider.DynamicDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
        <property name="captchaCheck">
        	<!-- 设置为false则不进行验证码的处理，默认设置为false -->
        	<value>false</value>
        </property>
    </bean>   
    
    <bean id="dynamicDaoAuthenticationProviderChinese"
          class="org.springside.modules.security.service.acegi.provider.DynamicDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImplChinese"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
        <property name="captchaCheck">
        	<!-- 设置为false则不进行验证码的处理，默认设置为false -->
        	<value>false</value>
        </property>
    </bean>  
    
    <bean id="kingdeeDaoAuthenticationProvider"
          class="org.springside.modules.security.service.acegi.provider.KingdeeDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
    </bean>
    
    <bean id="rtxDaoAuthenticationProvider"
          class="org.springside.modules.security.service.acegi.provider.RtxDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
    </bean>         
    
    <!-- PT056407, R111009-0403, hao_yun, 将v6.2R1中的IM集成回迁至v6.1 -->
    <bean id="ucstarDaoAuthenticationProvider"
          class="org.springside.modules.security.service.acegi.provider.UcstarDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
    </bean>          
    <bean id="ucstarDaoAuthenticationProviderEAS"
          class="org.springside.modules.security.service.acegi.provider.UcstarDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="ucstarJdbcDaoImpl"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
    </bean>     
    
    <bean id="rtxDaoAuthenticationProviderChinese"
          class="org.springside.modules.security.service.acegi.provider.RtxDaoAuthenticationProvider">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImplChinese"/>
        </property>
        <property name="userCache">
        	<ref local="userCache"/>
        </property>
        <property name="passwordEncoder">
        	<ref local="passwordEncoder"/>
        </property>
    </bean>
    <!--
         user缓存实际执行对象
         cacheManager见applicationContext.xml
     -->
    <bean id="userCacheBackend"
          class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager">
        	<ref bean="cacheManager"/>
        </property>
        <property name="cacheName">
        	<value>userCache</value>
        </property>
        <property name="maxElementsInMemory">
        	<value>2048</value>
        </property>
        <property name="eternal">
        	<value>true</value>
        </property>
        <property name="overflowToDisk">
        	<value>true</value>
        </property>        
    </bean>

    <bean id="userCache"
          class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"
          autowire="byName">
        <property name="cache">
        	<ref local="userCacheBackend"/>
        </property>
    </bean>

    <!-- 自建一个resourceCache以存放resource对应的role关系 -->
    <bean id="resourceCacheBackend"
          class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager">
        	<ref bean="cacheManager"/>
        </property>
        <property name="cacheName">
        	<value>resourceCache</value>
        </property>
        <property name="maxElementsInMemory">
        	<value>2048</value>
        </property>
        <property name="eternal">
        	<value>true</value>
        </property>
        <property name="overflowToDisk">
        	<value>true</value>
        </property>
    </bean>

    <!--
         resource缓存实际执行对象
     -->
    <bean id="resourceCache"
          class="org.springside.modules.security.service.acegi.cache.ResourceCache"
          autowire="byName">
        <property name="cache">
        	<ref local="resourceCacheBackend"/>
        </property>
    </bean>

    <bean id="testingAuthenticationProvider"
          class="org.acegisecurity.providers.TestingAuthenticationProvider"/>


    <!-- 自动接收 AuthenticationEvent 信息 -->
    <bean id="loggerListener"
          class="org.acegisecurity.event.authentication.LoggerListener"/>

    <!--
         用于处理HTTP头的认证信息，如从Spring远程协议(如Hessian和Burlap)或普通的浏览器如IE,Navigator的HTTP头中获取用户信息
     -->
    <bean id="basicProcessingFilter"
          class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
        <property name="authenticationManager">
        	<ref local="authenticationManager"/>
        </property>
        <property name="authenticationEntryPoint">
        	<ref local="basicProcessingFilterEntryPoint"/>
        </property>
    </bean>

    <!--
         处理基于HTTP的授权过程






         EntryPoint: 在当验证过程出现异常后的"去向"，通常实现转向、在response里加入error信息等功能。






         basicProcessingFilterEntryPoint在HTTP头交验失败后发送WWW-Authenticate头信息，并发送401(未验证)错误
     -->
    <bean id="basicProcessingFilterEntryPoint"
          class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
        <property name="realmName">
        	<value>SpringSide Realm</value>
        </property>
    </bean>

    <!--
         如果不存在任何授权信息时，自动添加匿名用户身份至SecurityContextHolder中






     -->
    <bean id="anonymousProcessingFilter"
          class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
        <property name="key">
        	<value>foobar</value>
        </property>
        <property name="userAttribute">
        	<value>anonymousUser,ROLE_ANONYMOUS</value>
        </property>
    </bean>

    <bean id="anonymousAuthenticationProvider"
          class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
        <property name="key">
        	<value>foobar</value>
        </property>
    </bean>

    <!--
         每次request前 HttpSessionContextIntegrationFilter从Session中获取Authentication对象，在request完后
         又把Authentication对象保存到Session中供下次request使用,此filter必须其他Acegi filter前使用






     -->
    <bean id="httpSessionContextIntegrationFilter"
          class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
    </bean>

    <!--
         当SecurityContextHolder中不存在Authentication.用户授权信息，






         rememberMeProcessingFilter就会调用autoLogin()方法从cookie中获取用户信息,在验证filter之前使用
     -->
    <bean id="rememberMeProcessingFilter"
          class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
        <property name="authenticationManager">
        	<ref local="authenticationManager"/>
        </property>
        <property name="rememberMeServices">
        	<ref local="rememberMeServices"/>
        </property>
    </bean>

    <!--
         提供rememberMe功能

         登陆验证时：登陆成功后会调用loginSuccess方法，在cookie里面保留用户信息，






         格式为：username + ":" + expiryTime + ":" + Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)

         访问页面时：rememberMeProcessingFilter会调用autoLogin方法，在cookie中获取用户信息






     -->
    <bean id="rememberMeServices"
          class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
        <property name="userDetailsService">
        	<ref local="jdbcDaoImpl"/>
        </property>
        <property name="key">
        	<value>springRocks</value>
        </property>
        <property name="parameter">
        	<value>rememberme</value>
        </property>
    </bean>

    <!--
         验证rememberMe证明信息的合法性，利用两个的key来进行比较验证






     -->
    <bean id="rememberMeAuthenticationProvider"
          class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
        <property name="key">
        	<value>springRocks</value>
        </property>
    </bean>

    <!--
         退出登陆并且remember-me cookie
     -->
    <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
        <!-- 退出后指向的，退出不彻底 URL -->
        <constructor-arg>
        	<value>/login/logout.jsp</value>
        </constructor-arg>
        <constructor-arg>
            <list>
            	<!-- 不用记住我hanyou, 2005.09.26 
                <ref bean="rememberMeServices"/>
                -->
                <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
                <ref bean="sessionLogoutHandler"/>
            </list>
        </constructor-arg>
    </bean>
    
    <bean id="sessionLogoutHandler" class="org.springside.modules.security.service.acegi.logout.SessionLogoutHandler">
    	<property  name="checkworkInfoManager">
        	<ref bean="checkworkInfoManager"/>
        </property>
        <property  name="userManager">
        	<ref bean="userManager"/>
        </property>
    </bean>
    
    

    <!--
         通过装饰模式，装饰的HttpServletRequest对象。






         其Wapper是ServletRequest包装类HttpServletRequestWrapper的子类(如:SavedRequestAwareWrapper或SecurityContextHolderAwareRequestWrapper)，






         附上获取用户权限信息，request参数，headers 和 cookies 的方法






     -->
    <bean id="securityContextHolderAwareRequestFilter"
          class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>

    <!-- ===================== HTTP REQUEST SECURITY ==================== -->
    <!-- 异常转换过滤器，主要是处理AccessDeniedException和AuthenticationException，将给每个异常找到合适的"去向"  -->
    <bean id="exceptionTranslationFilter"
          class="org.acegisecurity.ui.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
        	<ref local="authenticationProcessingFilterEntryPoint"/>
        </property>
    </bean>

    <!--
         和servlet spec差不多,处理登陆请求
         authenticationFailureUrl定义登陆失败时转向的页面
         defaultTargetUrl定义登陆成功时转向的页面
         filterProcessesUrl定义登陆请求的页面






         rememberMeServices用于在验证成功后添加cookie信息
     -->
    <bean id="authenticationProcessingFilter"
          class="org.springside.modules.security.service.acegi.filter.UserAuthenticationProcessingFilter">
        <property name="authenticationManager">
        	<ref local="authenticationManager"/>
        </property>
        <property name="authenticationFailureUrl">
            <value>/login/logout.jsp?login_error=1</value>
        </property>
        <property name="defaultTargetUrl">
            <value>/modules/home/portal.do</value>
        </property>
        <property name="filterProcessesUrl">
            <value>/j_acegi_security_check</value>
        </property>
        <property name="alwaysUseDefaultTargetUrl">
        	<value>true</value>
        </property>
        <property name="userManager">
            <ref bean="userManager"/>
        </property>
        <property name="deptManager">
            <ref bean="deptManager"/>
        </property>     
        <property name="messagesetsManager">
            <ref bean="messagesetsManager"/>
        </property>      
        <property name="messagesManager">
            <ref bean="messagesManager"/>
        </property> 
        <property name="checkworkInfoManager">
            <ref bean="checkworkInfoManager"/>
        </property>
        <property name="securitySettingsManager">
            <ref bean="securitySettingsManager"/>
        </property>
        
        <!--  
        <property name="rememberMeServices">
        	<ref local="rememberMeServices"/>
        </property>
        -->
    </bean>

    <!-- 当AccessDeniedException且存在anonymous user时触发 -->
    <bean id="authenticationProcessingFilterEntryPoint"
          class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
        <property name="loginFormUrl">
            <value>/login/logout.jsp</value>
        </property>
        <property name="forceHttps">
        	<value>false</value>
        </property>
    </bean>

    <!--
         经过投票机制来决定是否可以访问某一资源(URL或方法)
         allowIfAllAbstainDecisions为false时如果有一个或以上的decisionVoters投票通过,则授权通过
         可选的决策机制：






         ConsensusBased
         UnanimousBased
     -->
    <bean id="httpRequestAccessDecisionManager"
          class="org.acegisecurity.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions">
        	<value>false</value>
        </property>
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
            </list>
        </property>
    </bean>

    <!--
         filterInvocationInterceptor在执行转向url前检查objectDefinitionSource中设定的用户权限信息
         过程：






         首先，objectDefinitionSource中定义了访问URL需要的属性信息(这里的属性信息仅仅是标志，告诉accessDecisionManager要用哪些voter来投票)
         然后，authenticationManager掉用自己的provider来对用户的认证信息进行校验。






         最后，有投票者根据用户持有认证和访问url需要的属性，调用自己的voter来投票，决定是否允许访问。






     -->
    <bean id="filterInvocationInterceptor"
          class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager">
        	<ref local="authenticationManager"/>
        </property>
        <property name="accessDecisionManager">
        	<ref local="httpRequestAccessDecisionManager"/>
        </property>
        <property name="objectDefinitionSource">
        	<ref local="filterDefinitionSource"/>
        </property>
    </bean>
    <!-- ================= 自定义DBFilterInvocationDefinitionSource从数据库和cache中读取保护资源及其需要的访问权限信息 == -->
    <!--
		The mapping matches URLs using the following rules:
		? matches one character 
		* matches zero or more characters 
		** matches zero or more 'directories' in a path 
		?代表一个字符，因此我们将url的 ? 转换为 | 处理     
    -->
    <bean id="filterDefinitionSource"
          class="org.springside.modules.security.service.acegi.DBFilterInvocationDefinitionSource">
        <property name="convertUrlToLowercaseBeforeComparison">
        	<value>true</value>
        </property>
        <property name="useAntPath">
        	<value>true</value>
        </property>
        <property name="changeQuestionMark">
        	<value>true</value>
        </property>
        <property name="acegiCacheManager">
        	<ref bean="acegiCacheManager"/>
        </property>
    </bean> 

    <!--
         必须是以rolePrefix设定的value开头的才会进行投票,否则为弃权






     -->
    <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
        <property name="rolePrefix">
        	<value>AUTH_</value>
        </property>
    </bean>

</beans>
